另外一個我比較常用的例子是,用 Class 來寫 Table 的對應程式。
(不過應該有這種 Tool 可以幫您將 DB 的 Table 自動產生 Class 程式碼的)
不過因為物件的溝通是靠訊息及 Event 的傳遞,如果欄位太多,則對於物件屬性的存取反而會影響到 Performance(用 Debug Trace 一下就知道是怎麼回事了)。
那就讓我們就進入程式吧!
假設我有一個員工的資料表,Employee
CREATE TABLE [dbo].[Employee] (
[empy_id] [varchar] (6) NOT NULL ,
[empy_nm] [varchar] (8) NOT NULL ,
[dep_id] [varchar] (6) NOT NULL ,
[status] [char] (1) NOT NULL ,
[role] [char] (6) NOT NULL ,
[email] [varchar] (50) NULL
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Employee] ADD
CONSTRAINT [PK_Employee] PRIMARY KEY CLUSTERED
(
[empy_id]
) WITH FILLFACTOR = 90 ON [PRIMARY]
GO
有 Employee ID, Employee Name, Department ID, Role, Email, Status 等欄位。
我會建構一個 Class,clsEmployee 來與之對應:
Imports System.Data.SqlClient
Public Class clsEmployee
Private m_empy_id As String
Private m_empy_nm As String
Private m_dep_id As String
Private m_role As String
Private m_email As String
Private m_status As String
Public Property empy_id() As String
Get
Return m_empy_id
End Get
Set(ByVal value As String)
m_empy_id = Value
End Set
End Property
Public Property empy_nm() As String
Get
Return m_empy_nm
End Get
Set(ByVal value As String)
m_empy_nm = value
End Set
End Property
Public Property dep_id() As String
Get
Return m_dep_id
End Get
Set(ByVal value As String)
m_dep_id = value
End Set
End Property
Public Property role() As String
Get
Return m_role
End Get
Set(ByVal value As String)
m_role = value
End Set
End Property
Public Property email() As String
Get
Return m_email
End Get
Set(ByVal value As String)
m_email = value
End Set
End Property
Public Property status() As String
Get
Return m_status
End Get
Set(ByVal value As String)
m_status = value
End Set
End Property
Public Sub GetData(ByVal uid As String)
Dim conn As New SqlConnection
Dim cmd As New SqlCommand
Dim dr As SqlDataReader
Try
conn.ConnectionString = My.Settings.ConnectionString
conn.Open()
cmd.Connection = conn
cmd.CommandText = "select * from Employee where empy_id='" + uid + "'"
dr = cmd.ExecuteReader()
Do While dr.Read()
m_empy_id = dr.GetString(dr.GetOrdinal("empy_id"))
m_empy_nm = dr.GetString(dr.GetOrdinal("empy_nm"))
m_dep_id = dr.GetString(dr.GetOrdinal("dep_id"))
m_role = dr.GetString(dr.GetOrdinal("role"))
m_email = dr.GetString(dr.GetOrdinal("email"))
m_status = dr.GetString(dr.GetOrdinal("status"))
Loop
dr.Close()
Catch ex As Exception
Throw New System.Exception(ex.Message + vbCrLf + ex.StackTrace)
Finally
If conn.State = ConnectionState.Open Then
conn.Close()
End If
dr = Nothing
conn = Nothing
End Try
End Sub
Public Sub SaveData()
Dim conn As New SqlConnection
Dim cmd As New SqlCommand
Dim dr As SqlDataReader
'Dim trans As SqlTransaction
Try
conn.ConnectionString = My.Settings.ConnectionString
conn.Open()
'trans = conn.BeginTransaction()
cmd.Connection = conn
'cmd.Transaction = trans
cmd.CommandText = "select * from Employee where empy_id='" + empy_id + "'"
dr = cmd.ExecuteReader()
If dr.HasRows Then
dr.Close()
cmd.CommandText = "delete from Employee where empy_id='" + empy_id + "'"
cmd.ExecuteNonQuery()
End If
If Not dr.IsClosed Then dr.Close()
cmd.CommandText = "insert into Employee (empy_id,empy_nm,dep_id,role,email,status) values (?,?,?,?,?,?)"
cmd.Parameters.Clear()
cmd.Parameters.Add(New SqlParameter("?", m_empy_id))
cmd.Parameters.Add(New SqlParameter("?", m_empy_nm))
cmd.Parameters.Add(New SqlParameter("?", m_dep_id))
cmd.Parameters.Add(New SqlParameter("?", m_role))
cmd.Parameters.Add(New SqlParameter("?", m_email))
cmd.Parameters.Add(New SqlParameter("?", m_status))
cmd.ExecuteNonQuery()
'trans.Commit()
Catch ex As Exception
'If Not trans Is Nothing Then
' trans.Rollback()
'End If
Throw New System.Exception(ex.Message + vbCrLf + ex.StackTrace)
Finally
If conn.State = ConnectionState.Open Then
conn.Close()
End If
'trans = Nothing
dr = Nothing
conn = Nothing
End Try
End Sub
End Class
我可以在程式中宣告一個 Global 的物件,讓程式可以直接使用他,在 User 登入後,即將使用者的相關資料抓出來,存放於物件的屬性中(GetData()),如果使用者更改基本資料,那麼我也可以透過 SaveData() 將更新的資料回存到 Table 中,這樣在我的程式中,就不需要去撰寫那麼多的 SQL 存取指令,只要針對物件操作即可。
Dim oEmp As New clsEmployee
oEmp.GetData("A0001")
MsgBox(oEmp.email)
執行結果:
如果這個 Class 會經常用到,那麼將他做成 DLL 或者加入目前的專案,就可以重複使用了。
這是ActiveRecord嘛。
也許是吧...我沒有研究 ^^
應該是有更好的作法,只是沒有去找
感謝 fillano 大的提醒
http://en.wikipedia.org/wiki/Active_record_pattern
.Net 也有這個 Open Source 的 Framework
http://en.wikipedia.org/wiki/Castle_Project
Castle Project
http://www.castleproject.org/
感謝,讓我多學到好多!^^b
很好的概念,可是您的程式碼不會動,是不是可以修正一下
感謝大大提醒,確實有錯誤(寫了也沒有實際測試,真是慚愧)
GetData() 的 cmd 沒有指定 Connection 就使用是不合法的
還有 Class 宣告成 clsEmployee
物件宣告時卻 dim oEmp as Employee
所以會找不到
所以咯,以後我們發表文章一定要測試再測試,很多人若是看了文章然後跑不動就又懶得找出原因的話就會影響他們的學習興趣,這跟大大您的初衷就有相違背了。
您說得沒錯,確實給我寶貴的一課 ^^b
<pre class="c" name="code">Private _x As Integer
Public Property x() As Integer
Get
Return _x
End Get
Set(ByVal value As Integer)
_x = value
End Set
End Property
在 .NET 3.0 以上可以改寫成
<pre class="c" name="code">Public Property x As Integer = 10
Public Property y As New List(Of Integer)()
簡潔很多呦~ ^o^
參考:http://www.panopticoncentral.net/archive/2008/03/27/23050.aspx
嗯 這樣看起來就舒爽許多
當然,偷懶的話,也可以直接宣告 Public 直接拿來使用
不過這樣就比較沒有 Information Hiding 的概念了
感謝您提供資訊,現在 .Net 4.0 已經 Beta 了 Visual Studio 2010 Beta 2 也免費提供測試,得再 Renew 一下
我看到這個範例
就好希望只要寫一個XML
然後就有什麼XSLT或是什麼工具之類的
1.把XML轉成SQL DDL Script
2.把XML轉成class source code
3.把XML轉成HTML system document
一次滿足三個願望
豈不快哉 ^_^
ROR(不過Ruby我不熟)或是CakePHP,就可以達到類似的功能。
CakePHP有一個console程式叫做bake,在根據CakePHP的naming conversion做好DB後,就可以用bake產生module/view/controller的程式(scaffolding),當然要做出產品還是要花功夫。
相對於現成工具提供的產生器
或許自已開發一個產生器
會比較符合實際需求
功能不必非常強大
只要達到最小要求即可 ^_^
我有看過一些人這樣做,也是以xml為base。
嗯!我也都是習慣自己開發工具或是物件來協助我處理這類的資料存取
自訂XML格式,利用物件自動去存取DB
或是將DB中的TABLE Schema,匯出成XML格式!
自動產生Insert\Update的SQL Command
根據要抓的欄位,自動產生Select命令,以及外加條件式!
自行開發這些物件滿好玩的..!!
因為可以完全按照自己的想法和需求,自動化處理資料存取的功能!
有時候一行指令,就可以抓到我所需要的資料列以及所需的欄位..!!